﻿#include "sock.h"
#include "socket.h"
#include "raw.h"
#include "dgram.h"
#include "tools.h"
#include "routetbl.h"

static x_socket_t sock_tbl[SOCK_MAX_NR]; // 用于分配和存放socket

/**
 * @brief 从内存中分配socket
 * @return 分配的socket
 */
static x_socket_t *sock_alloc()
{
    x_socket_t *s = sock_tbl;
    for (int i = 0; i < SOCK_MAX_NR; ++i)
    {
        if (SOCKET_STATE_FREE == s->state)
        {
            s->state = SOCKET_STATE_USED;
            return s;
        }
        ++s;
    }

    return NULL;
}

/**
 * @brief 释放分配的socket
 */
static inline void sock_free(x_socket_t *s)
{
    if (!s)
        return;

    s->state = SOCKET_STATE_FREE;
}

/**
 * @brief 获取socket在数组中的下标
 */
static inline int sock_get_index(x_socket_t *s)
{
    if (!s)
        return -1;

    return (int)(s - sock_tbl);
}

/**
 * @brief 根据下标获取socket
 */
static inline x_socket_t *sock_get_socket(int index)
{
    if (index < 0 || index >= SOCK_MAX_NR)
        return NULL;
    if (sock_tbl[index].state == SOCKET_STATE_FREE)
        return NULL;
    return sock_tbl + index;
}

/**
 * @brief socket相关模块初始化
 */
net_err_t socket_init()
{
    DBG_INFO(DBG_SOCKET_LEVEL, "socket init begin!");
    plat_memset(sock_tbl, 0, sizeof(sock_tbl));

    DBG_INFO(DBG_SOCKET_LEVEL, "socket init end!");
    return NET_ERR_OK;
}

/**
 * @brief sock属性初始化
 * @param sock 需要被初始化的sock类型
 * @param family ip协议类型
 * @param protocol 传输协议类型
 * @param ops sock回调函数列表
 */
net_err_t sock_init(sock_t *sock, int family, int protocol, const sock_ops_t *ops)
{
    sock->local_port = 0;
    sock->remote_port = 0;
    ipaddr_set_any(&sock->local_ipaddr);
    ipaddr_set_any(&sock->remote_ipaddr);

    sock->ops = ops;
    sock->family = family;
    sock->protocol = protocol;
    sock->recv_tmo = 0;
    sock->send_tmo = 0;
    sock->err = NET_ERR_OK;
    nlist_node_init(&sock->node);

    sock->recv_wait = NULL;
    sock->send_wait = NULL;
    sock->conn_wait = NULL;

    return NET_ERR_OK;
}

/**
 * @brief 工作线程收到创建socket请求后调用的函数接口
 * @param msg 工作线程收到的消息
 */
net_err_t sock_create_req_in(struct _func_msg_t *msg)
{
    // 根据socket的不同的类型，调用不同的创建函数
    static const struct sock_info_t
    {
        int protocol;
        sock_t *(*create)(int family, int protocol);
    } sock_tbl[] = {
        [SOCK_RAW] = {.protocol = IPPROTO_ICMP, .create = raw_create},
        [SOCK_DGRAM] = {.protocol = IPPROTO_UDP, .create = dgram_create}};

    // 分配socket
    sock_req_t *req = (sock_req_t *)msg->param;
    sock_create_t *param = &req->create;
    x_socket_t *s = sock_alloc();
    if (!s)
    {
        DBG_WARNING(DBG_SOCKET_LEVEL, "alloc socket failed!");
        return NET_ERR_MEM;
    }

    // 根据socket类型，对其中的一些属性进行初始化
    // 先校验参数
    if (!param->protocol)
    {
        param->protocol = IPPROTO_ICMP;
    }
    if (param->type < 0 || param->type >= sizeof(sock_tbl) / sizeof(struct sock_info_t))
    {
        DBG_ERROR(DBG_SOCKET_LEVEL, "nosupport socket type:%d!", param->type);
        sock_free(s);
        return NET_ERR_PARAM;
    }

    // 获取对应的回调函数入口并进行调用
    const struct sock_info_t *info = sock_tbl + param->type;
    sock_t *sock = info->create(param->family, param->protocol);
    if (!sock)
    {
        DBG_ERROR(DBG_SOCKET_LEVEL, "sock create failed!");
        sock_free(s);
        return NET_ERR_MEM;
    }
    s->sock = sock;

    req->sockfd = sock_get_index(s);
    return NET_ERR_OK;
}

/**
 * @brief 工作线程收到通过socket发送数据时调用的接口
 *
 */
net_err_t sock_sendto_req_in(struct _func_msg_t *msg)
{
    sock_req_t *req = (sock_req_t *)msg->param;
    sock_data_t *param = &req->data;

    x_socket_t *s = sock_get_socket(req->sockfd);
    if (!s)
    {
        DBG_ERROR(DBG_SOCKET_LEVEL, "get socket by sockfd:%d failed!", req->sockfd);
        return NET_ERR_PARAM;
    }
    sock_t *sock = s->sock;

    if (!sock->ops->sendto)
    {
        DBG_ERROR(DBG_SOCKET_LEVEL, "the socket:%d sendto func in null!", req->sockfd);
        return NET_ERR_SYS;
    }

    net_err_t err = sock->ops->sendto(sock, param->buf, param->len, param->flags, (const struct x_sockaddr *)param->addr, (x_socklen_t)param->len, &param->comply);
    if (err == NET_ERR_NEEDWAIT)
    {
        if (sock->send_wait)
        {
            sock_wait_add(sock->send_wait, sock->send_tmo, req);
        }
    }
    return err;
}

/**
 * @brief 工作线程收到send请求后调用的函数
 */
net_err_t sock_send_req_in(struct _func_msg_t *msg)
{
    sock_req_t *req = (sock_req_t *)msg->param;
    sock_data_t *param = &req->data;
    x_socket_t *s = sock_get_socket(req->sockfd);
    if (!s)
    {
        DBG_ERROR(DBG_SOCKET_LEVEL, "get socket by sockfd:%d failed!", req->sockfd);
        return NET_ERR_PARAM;
    }
    sock_t *sock = s->sock;

    if (!sock->ops->send)
    {
        DBG_ERROR(DBG_SOCKET_LEVEL, "the socket:%d sendto func in null!", req->sockfd);
        return NET_ERR_SYS;
    }

    net_err_t err = sock->ops->send(sock, param->buf, param->len, param->flags, &param->comply);
    if (err == NET_ERR_NEEDWAIT)
    {
        if (sock->send_wait)
        {
            sock_wait_add(sock->send_wait, sock->send_tmo, req);
        }
    }
    return err;

    return NET_ERR_OK;
}

/**
 * @brief 工作线程收到通过socket接收数据请求时调用的接口
 */
net_err_t sock_recvfrom_req_in(struct _func_msg_t *msg)
{
    sock_req_t *req = (sock_req_t *)msg->param;
    sock_data_t *param = &req->data;

    x_socket_t *s = sock_get_socket(req->sockfd);
    if (!s)
    {
        DBG_ERROR(DBG_SOCKET_LEVEL, "get socket by sockfd:%d failed!", req->sockfd);
        return NET_ERR_PARAM;
    }
    sock_t *sock = s->sock;

    if (!sock->ops->recvfrom)
    {
        DBG_ERROR(DBG_SOCKET_LEVEL, "the socket:%d recvfrom func in null!", req->sockfd);
        return NET_ERR_SYS;
    }

    net_err_t err = sock->ops->recvfrom(sock, param->buf, param->len, param->flags, (struct x_sockaddr *)param->addr, param->addr_len, &param->comply);
    if (err == NET_ERR_NEEDWAIT)
    {
        if (sock->recv_wait)
        {
            sock_wait_add(sock->recv_wait, sock->recv_tmo, req);
        }
    }
    return err;
}

/**
 * @brief 工作线程收到recv请求时调用的接口
 */
net_err_t sock_recv_req_in(struct _func_msg_t *msg)
{
    sock_req_t *req = (sock_req_t *)msg->param;
    sock_data_t *param = &req->data;

    x_socket_t *s = sock_get_socket(req->sockfd);
    if (!s)
    {
        DBG_ERROR(DBG_SOCKET_LEVEL, "get socket by sockfd:%d failed!", req->sockfd);
        return NET_ERR_PARAM;
    }
    sock_t *sock = s->sock;

    if (!sock->ops->recv)
    {
        DBG_ERROR(DBG_SOCKET_LEVEL, "the socket:%d recvfrom func in null!", req->sockfd);
        return NET_ERR_SYS;
    }

    net_err_t err = sock->ops->recv(sock, param->buf, param->len, param->flags, &param->comply);
    if (err == NET_ERR_NEEDWAIT)
    {
        if (sock->recv_wait)
        {
            sock_wait_add(sock->recv_wait, sock->recv_tmo, req);
        }
    }
    return err;
}

/**
 * @brief 工作线程收到setsockopt请求后调用的函数
 */
net_err_t sock_setsockopt_req_in(struct _func_msg_t *msg)
{
    sock_req_t *req = (sock_req_t *)(msg->param);
    sock_opt_t *opt = &req->opt;

    x_socket_t *s = sock_get_socket(req->sockfd);
    if (!s)
    {
        DBG_ERROR(DBG_SOCKET_LEVEL, "get socket by sockfd:%d failed!", req->sockfd);
    }
    sock_t *sock = s->sock;
    return sock_setopt(sock, opt->level, opt->optname, opt->optval, opt->len);
}

/**
 * @brief 工作线程收到connect请求后调用的函数
 */
net_err_t sock_connect_req_in(struct _func_msg_t *msg)
{
    sock_req_t *req = (sock_req_t *)(msg->param);
    x_socket_t *s = sock_get_socket(req->sockfd);
    if (!s)
    {
        DBG_ERROR(DBG_SOCKET_LEVEL, "get socket by sockfd:%d failed!", req->sockfd);
    }
    sock_t *sock = s->sock;
    if (!sock->ops->connect)
    {
        DBG_ERROR(DBG_SOCKET_LEVEL, "the socket:%d connect func in null!", req->sockfd);
        return NET_ERR_SYS;
    }

    sock_conn_t conn_param = req->connect;
    net_err_t err = sock->ops->connect(sock, conn_param.addr, conn_param.addrlen);
    if (err == NET_ERR_NEEDWAIT)
    {
        if (sock->conn_wait)
        {
            sock_wait_add(sock->conn_wait, sock->recv_tmo, req);
        }
    }

    return NET_ERR_OK;
}

/**
 * @brief 工作线程收到bind请求后调用的函数
 */
net_err_t sock_bind_req_in(struct _func_msg_t *msg)
{
    sock_req_t *req = (sock_req_t *)(msg->param);
    x_socket_t *s = sock_get_socket(req->sockfd);
    if (!s)
    {
        DBG_ERROR(DBG_SOCKET_LEVEL, "get socket by sockfd:%d failed!", req->sockfd);
    }
    sock_t *sock = s->sock;
    if (!sock->ops->bind)
    {
        DBG_ERROR(DBG_SOCKET_LEVEL, "the socket:%d connect func in null!", req->sockfd);
        return NET_ERR_SYS;
    }

    sock_bind_t bind_param = req->bind;
    net_err_t err = sock->ops->bind(sock, bind_param.addr, bind_param.addrlen);
    if (err == NET_ERR_NEEDWAIT)
    {
        if (sock->conn_wait)
        {
            sock_wait_add(sock->conn_wait, sock->recv_tmo, req);
        }
    }

    return NET_ERR_OK;
}

/**
 * @brief 工作线程收到close请求后调用的函数接口
 */
net_err_t sock_close_req_in(struct _func_msg_t *msg)
{
    sock_req_t *req = (sock_req_t *)(msg->param);

    x_socket_t *s = sock_get_socket(req->sockfd);
    if (!s)
    {
        DBG_ERROR(DBG_SOCKET_LEVEL, "get socket by sockfd:%d failed!", req->sockfd);
    }
    sock_t *sock = s->sock;
    if (!sock->ops->close)
    {
        DBG_ERROR(DBG_SOCKET_LEVEL, "the socket:%d close func in null!", req->sockfd);
        return NET_ERR_SYS;
    }
    net_err_t err = sock->ops->close(sock);
    if (err < NET_ERR_OK)
    {
        DBG_ERROR(DBG_RAW_LEVEL, "close socket:%d failed!", req->sockfd);
    }

    sock_free(s);

    return err;
}

/**
 * @brief sock等待相关参数初始化
 */
net_err_t sock_wait_init(sock_wait_t *wait)
{
    wait->sem = sys_sem_create(0);
    if (wait->sem == SYS_SEM_INVALID)
    {
        DBG_ERROR(DBG_SOCKET_LEVEL, "wait sem create failed in sock wait init!");
        return NET_ERR_SYS;
    }
    wait->err = NET_ERR_OK;
    wait->waiting = 0;

    return NET_ERR_OK;
}

/**
 * @brief 释放请求相关参数
 */
void sock_wait_destroy(sock_wait_t *wait)
{
    if (wait->sem != SYS_SEM_INVALID)
    {
        sys_sem_free(wait->sem);
    }
}

/**
 * @brief 由工作线程调用，向socket请求中添加等待相关参数
 * @param wait 等待参数
 * @param tmo 超时时间，单位ms
 * @param req socket请求
 */
void sock_wait_add(sock_wait_t *wait, int tmo, sock_req_t *req)
{
    ++wait->waiting;
    req->wait = wait;
    req->wait_tmo = tmo;
}

/**
 * @brief 由应用程序调用，让应用程序接口处陷入等待
 * @param wait 等待相关参数
 * @param tmo 超时时间
 */
net_err_t sock_wait_enter(sock_wait_t *wait, int tmo)
{
    if (sys_sem_wait(wait->sem, tmo) < 0)
    {
        return NET_ERR_TMO;
    }

    return wait->err;
}

/**
 * @brief
 */
void sock_wait_leave(sock_wait_t *wait, net_err_t err)
{
    if (wait->waiting > 0)
    {
        --wait->waiting;
        sys_sem_notify(wait->sem);
        wait->err = err;
    }
}

/**
 * @brief sock相关资源释放
 */
net_err_t sock_uninit(sock_t *sock)
{
    if (sock->recv_wait)
    {
        sock_wait_destroy(sock->recv_wait);
    }
    if (sock->send_wait)
    {
        sock_wait_destroy(sock->send_wait);
    }
    if (sock->conn_wait)
    {
        sock_wait_destroy(sock->conn_wait);
    }

    return NET_ERR_OK;
}

/**
 * @brief 唤醒正在等待的线程
 * @param sock sock相关参数
 * @param type 被唤起的等待唤醒类型
 * @param err  唤醒错误码
 */
void sock_wakeup(sock_t *sock, int type, int err)
{
    if (type & SOCK_WAIT_READ)
    {
        sock_wait_leave(sock->recv_wait, err);
    }
    if (type & SOCK_WAIT_WRITE)
    {
        sock_wait_leave(sock->send_wait, err);
    }
    if (type & SOCK_WAIT_CONN)
    {
        sock_wait_leave(sock->conn_wait, err);
    }
}

/**
 * @brief 通用设置socket超时等相关属性
 * @param s sock相关参数
 */
net_err_t sock_setopt(struct _sock_t *s, int level, int optname, const char *optval, int optlen)
{
    if (SOL_SOCKET == level)
    {
        switch (optname)
        {
        case SO_RCVTIMEO:
        case SO_SNDTIMEO:
        {
            // 设置发送和接收超时，设置参数需为x_timeval类型
            if (sizeof(struct x_timeval) != optlen)
            {
                DBG_ERROR(DBG_SOCKET_LEVEL, "the param of optval or optlen is error!");
                return NET_ERR_PARAM;
            }
            struct x_timeval *time = (struct x_timeval *)optval;
            int time_ms = time->tv_sec * 1000 + time->tv_usec / 1000;
            if (SO_RCVTIMEO == optname)
            {
                s->recv_tmo = time_ms;
            }
            else if (SO_SNDTIMEO == optname)
            {
                s->send_tmo = time_ms;
            }
            return NET_ERR_OK;
            break;
        }
        default:
        {
            DBG_WARNING(DBG_SOCKET_LEVEL, "the optname:%d doesn't support!", optname);
            return NET_ERR_NOSUPPORT;
        }
        }
    }
    else
    {
        DBG_WARNING(DBG_SOCKET_LEVEL, "the level of setopt doesn't support!");
        return NET_ERR_NOSUPPORT;
    }
}

/**
 * @brief connect命令通用调用接口
 */
net_err_t sock_connect(struct _sock_t *s, const struct x_sockaddr *addr, x_socklen_t addrlen)
{
    if (addrlen != sizeof(struct x_sockaddr_in))
    {
        DBG_ERROR(DBG_SOCKET_LEVEL, "the param of addr or addrlen is error in sock connect!");
        return NET_ERR_PARAM;
    }
    const struct x_sockaddr_in *dst_addr = (const struct x_sockaddr_in *)addr;
    s->remote_port = x_ntohs(dst_addr->sin_port);
    s->remote_ipaddr.q_addr = dst_addr->sin_addr.s_addr;
    return NET_ERR_OK;
}

/**
 * @brief send命令通用调用接口
 */
net_err_t sock_send(struct _sock_t *s, const void *buf, size_t len, int flags, ssize_t *result_len)
{
    struct x_sockaddr_in addr;
    if (ipaddr_is_any(&s->remote_ipaddr))
    {
        DBG_ERROR(DBG_SOCKET_LEVEL, "remote addr is null, can't use send func!");
        return NET_ERR_SYS;
    }

    addr.sin_family = s->family;
    addr.sin_port = x_ntohs(s->remote_port);
    addr.sin_addr.s_addr = s->remote_ipaddr.q_addr;

    return s->ops->sendto(s, buf, len, flags, (const struct x_sockaddr *)&addr, sizeof(addr), result_len);
}

/**
 * @brief recv命令通用调用接口
 */
net_err_t sock_recv(struct _sock_t *s, void *buf, size_t len, int flags, ssize_t *result_len)
{
    struct x_sockaddr_in addr;
    x_socklen_t addr_len = sizeof(addr);

    return s->ops->recvfrom(s, buf, len, flags, (struct x_sockaddr *)&addr, &addr_len, result_len);
}

/**
 * @brief bind通用调用接口
 */
net_err_t sock_bind(struct _sock_t *s, const ipaddr_t *ip, int port)
{
    // 检查ip地址是否有效，即协议栈中必须存在对应ip地址的网卡
    if(!ipaddr_is_any(ip))
    {
        route_entry_t *route_entry = routetbl_find(ip);
        if(!route_entry || !ipaddr_is_equal(&route_entry->netif->ipaddr, ip))
        {
            DBG_ERROR(DBG_SOCKET_LEVEL, "the ipaddr is invalid in sock_bind!");
            return NET_ERR_PARAM;
        }
    }

    ipaddr_copy(&s->local_ipaddr, ip);
    s->local_port = port;

    return NET_ERR_OK;
}